#include <iostream>
#include <exception>

#include "interpreter.h"
#include "instructions/instruction_factory.h"
//#include "rtda/heap/object.h"
#include "rtda/heap/class.h"
#include "rtda/heap/class_loader.h"
#include "rtda/heap/string_pool.h"
#include <variant>

//#include "native/registry.h"
//#include "native/java/lang/Class.hpp"
//#include "native/java/lang/Object.hpp"
//#include "native/java/lang/Float.hpp"
//#include "native/java/lang/System.hpp"
//#include "native/java/lang/String.hpp"
//#include "native/java/lang/Double.hpp"
//#include "native/java/lang/Throwable.hpp"
//#include "native/sun/misc/VM.h"

namespace jvm {

    heap::ObjectPtr createArgsArray(std::shared_ptr<heap::ClassLoader> ploder, const std::vector<std::string>& args)
    {
        auto&& strClass = ploder->loadClass("java/lang/String");
        auto&& argsArray = strClass->getArrayClass()->newArray(args.size());
        auto&& jArgs = argsArray->refs();
        for (int i = 0; i < args.size(); ++i)
        {
            jArgs[i] = heap::StringPool::getInstance().JString(ploder, args[i]);
        }
        return argsArray;
    }

//void Interpreter::interpret(std::shared_ptr<heap::Method> methodInfo, bool logInst, const std::vector<std::string>& args) 
void Interpreter::interpret(std::shared_ptr<rtda::Thread> thread, bool logInst)
{
    // auto codeAttr = methodInfo->getCodeAttribute();
    // uint16_t maxLocals = codeAttr->getMaxLocals();
    // uint16_t maxStack = codeAttr->getMaxStack();
    // auto bytecode = codeAttr->getCode();

    //lang::ClassNative::init();
    //lang::ObjectNative::init();
    //lang::FloatNative::init();
    //lang::DoubleNative::init();
    //lang::SystemNative::init();
    //lang::StringNative::init();
    //lang::ThrowableNative::init();
    //misc::VMNative::init();

    //auto thread = std::make_shared<rtda::Thread>();
    //auto frame = thread->newFrame(methodInfo);
    //thread->pushFrame(frame);

    //auto&& jArgs = createArgsArray(methodInfo->getClass()->getLoder(), args);
    //frame->getLocalVars().setRef(0, jArgs);

    try {
        loop(thread, logInst);
    } catch (...) {
        catchErr(thread);
        throw; // 重新抛出异常
    }
}

void Interpreter::catchErr(std::shared_ptr<rtda::Thread> thread) {
    try {
        // 检查当前异常（相当于Go的recover()）
        if (std::exception_ptr eptr = std::current_exception()) {
            LOG_ERROR("Interpreter::catchErr");
            logFrames(thread);  // 记录栈帧
            std::rethrow_exception(eptr);  // 重新抛出
        }
    }
    // 捕获已知异常
    catch (const std::exception& e) {
        //std::cerr << "捕获异常: " << e.what() << std::endl;
        LOG_ERROR("Interpreter::catchErr: " << e.what());
        logFrames(thread);
        throw;  // 重新抛出
    }
    // 捕获未知异常（相当于Go的通用recover）
    catch (...) {
        //std::cerr << "捕获未知异常" << std::endl;
        LOG_ERROR("Interpreter::catchErr: ");
        logFrames(thread);
        throw;
    }
}

void Interpreter::logFrames(std::shared_ptr<rtda::Thread> thread)
{
    while (!thread->isStackEmpty()) {
        auto frame = thread->popFrame();
        auto method = frame->getMethod();
        auto className = method->getClass()->getName();

        std::cout << ">> pc:" << std::setw(4) << frame->getNextPC() << " "
            << className << "." << method->getName()
            << method->getDescriptor() << std::endl;
    }
}

void Interpreter::logInstruction(std::shared_ptr<rtda::Frame> frame, std::shared_ptr<instructions::Instruction> inst)
{
    auto method = frame->getMethod();
    auto className = method->getClass()->getName();
    auto&& methodName = method->getName();
    auto pc = frame->getThread()->getPC();

    std::cout << className << "." << methodName << "() #"
        << std::setw(2) << pc << " "
        << typeid(*inst).name() << std::endl;
    //<< inst->to_string() << std::endl;
}

void Interpreter::logInstruction(std::shared_ptr<rtda::Frame> frame, instructions::Instruction* inst)
{
    auto method = frame->getMethod();
    auto className = method->getClass()->getName();
    auto&& methodName = method->getName();
    auto pc = frame->getThread()->getPC();

    std::cout << className << "." << methodName << "() #"
        << std::setw(2) << pc << " "
        << typeid(*inst).name() << std::endl;
    //<< inst->to_string() << std::endl;
}

//void Interpreter::loop(std::shared_ptr<rtda::Thread> thread, const std::vector<uint8_t>& bytecode, bool logInst) {
void Interpreter::loop(std::shared_ptr<rtda::Thread> thread, bool logInst)
{
    //auto frame = thread->popFrame();
    auto reader = std::make_shared<instructions::BytecodeReader>();
    static size_t check_gc = 128;

    while (true) {
        auto frame = thread->currentFrame();
        uint32_t pc = frame->getNextPC();
        thread->setPC(pc);

        // 解码指令
        reader->reset(frame->getMethod()->getCode(), pc);
        uint8_t opcode = reader->readUint8();
        instructions::InstructionPtr inst_ptr = instructions::InstructionFactory::newInstruction(opcode);

        // 尝试提取原始指针
        if (auto p = std::get_if<instructions::Instruction*>(&inst_ptr)) {
            // 使用原始指针
            instructions::Instruction* pinst = *p;

            pinst->fetchOperands(reader);
            frame->setNextPC(reader->getPc());

            if (logInst) logInstruction(frame, pinst);

            // 执行指令
            pinst->execute(frame);
            if (thread->isStackEmpty()) break;
        }
        // 尝试提取shared_ptr
        else if (auto p = std::get_if<std::shared_ptr<instructions::Instruction>>(&inst_ptr)) {
            // 使用shared_ptr管理的指针
            auto&& pinst = *p;

            pinst->fetchOperands(reader);
            frame->setNextPC(reader->getPc());

            if (logInst) logInstruction(frame, pinst);

            // 执行指令
            //std::cout << "pc:" << pc << " inst:" << typeid(*inst).name() << std::endl;
            pinst->execute(frame);
            if (thread->isStackEmpty()) break;
        }
        else
        {
            LOG_ERROR("Unknown error!");
        }

        // 手动gc
        if (heap::GC::g_s_gc.size() >= check_gc)
        {
            check_gc *= 2;

            std::cout << "GC working check gc size: " << check_gc << std::endl;

            heap::GC::g_s_gc.unmark();
            // 标记
            auto&& frames = thread->getFrames(); // 获取所有栈帧
            for (auto& frame : frames)
            {
                auto&& loacl_vars = frame->getLocalVars(); // 局部变量表
                auto&& op_stack = frame->getOperandStack(); // 操作数栈

                for (int i = 0; i < loacl_vars.size(); ++i)
                {
                    heap::ObjectPtr pobj = loacl_vars.getRef(i);
                    if (nullptr != pobj)
                    {
                        pobj->mark();
                    }

                }

                for (auto& slot : op_stack->get_slots())
                {
                    heap::ObjectPtr pobj = slot.getRef();
                    if (nullptr != pobj)
                    {
                        pobj->mark();
                    }
                }
            }

            // 清除
            //heap::GC::g_s_gc.sweep();
        }

    }
}

} // namespace jvm